/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.tencent.tendon.convert.json;

import java.lang.reflect.*;
import com.tencent.tendon.convert.util.*;

/**
 *
 * @author nbzhang
 */
public class JsonArrayDecoder<T> extends JsonDecoder<T[]> {

	private final JsonDecodable<T> decoder;

	private final Class<T> component;

	JsonArrayDecoder(final Type type) {
		super(type);
		if (type instanceof GenericArrayType) {
			Type comp = ((GenericArrayType) type).getGenericComponentType();
			this.decoder = JsonLoader.loadDecodable(comp);
			if (comp instanceof Class) {
				this.component = (Class) comp;
			} else if (comp instanceof ParameterizedType) {
				ParameterizedType pt = (ParameterizedType) comp;
				if (pt.getRawType() instanceof Class) {
					this.component = (Class) pt.getRawType();
				} else {
					this.component = null;
				}
			} else {
				this.component = null;
			}
		} else if (type instanceof Class && ((Class) type).isArray()) {
			this.component = ((Class) type).getComponentType();
			this.decoder = JsonLoader.loadDecodable(this.component);
		} else {
			throw new JsonException("not support the type (" + type + ")");
		}
		this.simpled = decoder.isSimpled();
	}

	private JsonArrayDecoder(final Class<T[]> type, final Class componentType, final JsonDecodable<T> decoder) {
		super(type);
		this.component = componentType;
		this.decoder = decoder;
		this.simpled = decoder.isSimpled();
	}

	public static <T> JsonArrayDecoder<T> create(final Type componentType, final JsonDecodable<T> decoder) {
		Class component = null;
		if (componentType instanceof Class) {
			component = (Class) componentType;
		} else if (componentType instanceof ParameterizedType) {
			ParameterizedType pt = (ParameterizedType) componentType;
			if (pt.getRawType() instanceof Class) component = (Class) pt.getRawType();
		}
		Class clazz = component == null ? null : Array.newInstance(component, 0).getClass();
		return new JsonArrayDecoder(clazz, component, decoder);
	}

	@Override
	public T[] convertFrom(final JsonReader in) {
		final AnyArray<T> result = JsonPool.pollAnyArray();
		if (!simpled) in.offer(result);
		in.checkArray();
		final JsonDecodable<T> localdecoder = this.decoder;
		while (in.hasNext()) {
			result.add(localdecoder.convertFrom(in));
		}
		if (!simpled) in.poll();
		T[] data = (component == null) ? result.toArray() : result.toArray(component);
		JsonPool.offer(result);
		return data;
	}

	@Override
	public String toString() {
		return this.getClass().getSimpleName() + "{decoder : " + decoder + "}";
	}

	private static Class parseRawType(final Type type) {
		if (type instanceof GenericArrayType) {
			return parseRawType(((GenericArrayType) type).getGenericComponentType());
		} else if (type instanceof ParameterizedType) {
			return parseRawType(((ParameterizedType) type).getRawType());
		} else if (type instanceof Class) {
			return (Class) type;
		} else {
			throw new JsonException("not support the type (" + type + ")");
		}
	}
}
